﻿using System;
using System.Diagnostics;
using System.Management;
using System.ServiceProcess;
using System.Threading;
using AccessControl.Utility.Tools;

namespace AccessControl.AccessControlAgent
{
    public class ServiceManager
    {

        #region Fields
        private static ServiceController targetServiceController;
        private static Process targetServiceProcess;
        private static bool isRestarting;

        #endregion

        #region Methods

        public static bool FindService()
        {
            var services = ServiceController.GetServices();
            foreach (var serviceController in services)
            {
                if (serviceController.ServiceName != Properties.Settings.Default.ServiceName) continue;
                targetServiceController = serviceController;
                return true;
            }
            return false;
        }

        public static void CheckAlive()
        {
            if (targetServiceController == null)
            {
                if (!FindService())
                    return;
            }
            if (isRestarting)
                return;

            if (targetServiceController.Status != ServiceControllerStatus.Running
                || !HasProcess()){

                isRestarting = true;

                AccessControlAgent.ServiceInstance.WriteLog("Service Stopped, Restarting Service", eventLevelConstants.Info);

                if (RestartService())
                    AccessControlAgent.ServiceInstance.WriteLog("Service restarted successfully", eventLevelConstants.Info);

                isRestarting = false;

            }
        }

        public static bool RestartService(){
            var result = false;
            try{
                isRestarting = true;
                StopService();

                while ((targetServiceProcess != null && !targetServiceProcess.HasExited))
                    Thread.Sleep(3);

                result=StartServie();

                return result;
            }
            catch (Exception ex){

                AccessControlAgent.ServiceInstance.WriteLog("Failed restarting service, " + ex.Message, eventLevelConstants.Error);
            }finally{
                isRestarting = false;
            }
            return result;
        }

        public static bool StopService(){
            try
            {
                if (GetServiceStatus() != ServiceControllerStatus.Stopped)
                {
                    targetServiceController.Stop();
                    Thread.Sleep(3);
                }

                if (HasProcess())
                    targetServiceProcess.Kill();

                return true;
            }
            //catch (Win32Exception)
            //{
            //    // Thrown if process is already terminating,
            //    // the process is a Win16 exe or the process
            //    // could not be terminated.
            //}
            catch (Exception ex)
            {
                AccessControlAgent.ServiceInstance.WriteLog("Error stopping service, " + ex.Message, eventLevelConstants.Error);
            }
            return false;
        }

        public static ServiceControllerStatus GetServiceStatus(){
            try{
                if (targetServiceController == null)
                    return ServiceControllerStatus.Stopped;

                targetServiceController.Refresh();
                return targetServiceController.Status;
            }
            catch (Exception ex){
                AccessControlAgent.ServiceInstance.WriteLog("Error retreiving service service statis, " + ex.Message, eventLevelConstants.Error);
            }
            return ServiceControllerStatus.Stopped;
        }

        public static bool StartServie(){
            try
            {
                if (GetServiceStatus() == ServiceControllerStatus.Running) 
                    return true;

                targetServiceController.Start();


                var t = Environment.TickCount;
                while (GetServiceStatus() == ServiceControllerStatus.Running)
                {
                    Thread.Sleep(3);
                    if(Environment.TickCount-t>10000) 
                        throw new Exception("Starting service took too long!");
                }
                AccessControlAgent.ServiceInstance.WriteLog("Service Started successfully", eventLevelConstants.Info);

                return true;
            }
            //catch (InvalidOperationException ex)
            //{
            //    //
            //}
            catch (Exception ex)
            {
                AccessControlAgent.ServiceInstance.WriteLog("Error starting service, " + Properties.Settings.Default.ServiceName + ", " + ex.Message, eventLevelConstants.Error);
            }

            return false;
        }

        private static bool HasProcess()
        {
            try{
                if (targetServiceProcess == null || targetServiceProcess.HasExited)
                {
                    var query = string.Format("SELECT ProcessId FROM Win32_Service WHERE Name='{0}'", Properties.Settings.Default.ServiceName);
                    var searcher = new ManagementObjectSearcher(query);
                    foreach (ManagementObject obj in searcher.Get())
                    {
                        var processId = (uint)obj["ProcessId"];
                        if (processId == 0) continue;
                        try
                        {
                            targetServiceProcess = Process.GetProcessById((int)processId);
                            //serviceProcess.Exited += ProcessExited;
                            return true;
                        }
                        catch (ArgumentException)
                        {
                            return false;
                        }

                    }
                    return false;
                }

                return true;
                
            }
                
            catch (Exception ex){
                AccessControlAgent.ServiceInstance.WriteLog("Error starting service, " + Properties.Settings.Default.ServiceName + ", " + ex.Message, eventLevelConstants.Error);
            }

            return false;
        }


        #endregion
    }
}
